<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
  PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
<topic id="topic1" xml:lang="en">
  <title id="py212122">Greenplum Partner Connector API</title>
  <body>
      <p>With the Greenplum Partner Connector API (GPPC API), you can write
        portable Greenplum Database user-defined functions (UDFs) in the C and
        C++ programming languages. Functions that you develop with the GPPC API
        require no recompilation or modification to work with older or newer
        Greenplum Database versions.</p>
      <p>Functions that you write to the GPPC API can be invoked using SQL
        in Greenplum Database. The API provides a set of functions and macros
        that you can use to issue SQL commands through the Server Programming
        Interface (SPI), manipulate simple and composite data type function
        arguments and return values, manage memory, and handle data.</p>
      <p>You compile the C/C++ functions that you develop with the GPPC API
        into a shared library. The GPPC functions are available to Greenplum
        Database users after the shared library is installed in the Greenplum
        Database cluster and the GPPC functions are registered as SQL UDFs.</p>
      <note>The Greenplum Partner Connector is supported for Greenplum Database
        versions 4.3.5.0 and later.</note>
    <p>This topic contains the following information:</p>
    <ul>
      <li id="py219392">
        <xref href="#topic_dev" type="topic" format="dita"/><ul>
          <li><xref href="#topic_reqs" type="topic" format="dita"/></li>
          <li><xref href="#topic_files" type="topic" format="dita"/></li>
          <li><xref href="#topic_data" type="topic" format="dita"/></li>
          <li><xref href="#topic_argres" type="topic" format="dita"/></li>
          <li><xref href="#topic_mem" type="topic" format="dita"/></li>
          <li><xref href="#topic_varlentext" type="topic" format="dita"/></li>
          <li><xref href="#topic_errrpt" type="topic" format="dita"/></li>
          <li><xref href="#topic_spi" type="topic" format="dita"/></li>
          <li><xref href="#topic_tuple" type="topic" format="dita"/></li>
          <li><xref href="#topic_srf" type="topic" format="dita"/></li>
          <li><xref href="#topic_tblfunc" type="topic" format="dita"/></li>
          <li><xref href="#topic_limits" type="topic" format="dita"/></li>
          <li><xref href="#topic_samplecode" type="topic" format="dita"/></li>
        </ul>
      </li>
      <li id="py219393">
        <xref href="#topic_build" type="topic" format="dita"/>
      </li>
      <li id="py219391">
        <xref href="#topic_reg" type="topic" format="dita"/>
      </li>
      <li id="py219394">
        <xref href="#topic_deploy" type="topic" format="dita"/>
      </li>
      <li id="py219396">
        <xref href="#topic_example_text" type="topic" format="dita"/>
      </li>
      <li id="py219397">
        <xref href="#topic_example_srf" type="topic" format="dita"/>
      </li>
    </ul>
  </body>

  <topic id="topic_dev" xml:lang="en">
    <title id="py21716799">Using the GPPC API</title>
    <body>
      <p>The GPPC API shares some concepts with C language functions as defined
        by PostgreSQL. Refer to <xref href="https://www.postgresql.org/docs/9.4/xfunc-c.html" format="html" scope="external">C-Language Functions</xref>
        in the PostgreSQL documentation for detailed information about developing
        C language functions.</p>
      <p>The GPPC API is a wrapper that makes a C/C++ function SQL-invokable
        in Greenplum Database. This wrapper shields GPPC functions that you
         write from Greenplum Database library changes by normalizing table
         and data manipulation and SPI operations through functions and macros
         defined by the API.</p>
      <p>The GPPC API includes functions and macros to:</p><ul>
        <li>Operate on base and composite data types.</li>
        <li>Process function arguments and return values.</li>
        <li>Allocate and free memory.</li>
        <li>Log and report errors to the client.</li>
        <li>Issue SPI queries.</li>
        <li>Return a table or set of rows.</li>
        <li>Process tables as function input arguments.</li>
      </ul>
    </body>
    <topic id="topic_reqs" xml:lang="en">
      <title id="py217167">Requirements</title>
      <body>
        <p>When you develop with the GPPC API:</p><ul>
          <li>You must develop your code on a system with the same hardware and
            software architecture as that of your Greenplum Database hosts.</li>
          <li>You must write the GPPC function(s) in the C or C++ programming 
            languages.</li>
          <li>The function code must use the GPPC API, data types, and macros.</li>
          <li>The function code must <i>not</i> use the PostgreSQL C-Language
            Function API, header files, functions, or macros.</li>
          <li>The function code must <i>not</i> <codeph>#include</codeph> the
            <codeph>postgres.h</codeph> header file or use <codeph>PG_MODULE_MAGIC</codeph>.</li>
          <li>You must use only the GPPC-wrapped memory functions to allocate
            and free memory. See <xref href="#topic_mem" format="dita"/>.</li>
          <li>Symbol names in your object files must not conflict with each
            other nor with symbols defined in the Greenplum Database server.
            You must rename your functions or variables if you get error messages
            to this effect.</li>
        </ul>
      </body>
    </topic>
    <topic id="topic_files" xml:lang="en">
      <title id="py217167">Header and Library Files</title>
      <body>
        <p>The GPPC header files and libraries are installed in 
          <codeph>$GPHOME</codeph>:</p><ul>
          <li>$GPHOME/include/gppc.h - the main GPPC header file</li>
          <li>$GPHOME/include/gppc_config.h - header file defining the GPPC
            version</li>
          <li>$GPHOME/lib/libgppc.[a, so, so.1, so.1.2] - GPPC archive and
            shared libraries</li>
        </ul>
      </body>
    </topic>
    <topic id="topic_data" xml:lang="en">
      <title id="py217167">Data Types</title>
      <body>
        <p>The GPPC functions that you create will operate on data residing
          in Greenplum Database. The GPPC API includes data type definitions for equivalent
          Greenplum Database SQL data types. You must use these types in your
          GPPC functions.</p>
        <p>The GPPC API defines a generic data type that you can use to
          represent any GPPC type.
          This data type is named <codeph>GppcDatum</codeph>, and is defined
          as follows:
          <codeblock>typedef int64_t GppcDatum;</codeblock></p>
        <p>The following table identifies each GPPC data type and the SQL
          type to which it maps.</p>
        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="77*"/>
          <colspec colname="col2" colnum="2" colwidth="86*"/>
          <colspec colname="col2" colnum="3" colwidth="86*"/>
          <thead>
            <row>
              <entry colname="col1">SQL Type</entry>
              <entry colname="col2">GPPC Type</entry>
              <entry colname="col3">GPPC Oid for Type</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">boolean</entry>
              <entry colname="col2">GppcBool</entry>
              <entry colname="col3">GppcOidBool</entry>
            </row>
            <row>
              <entry colname="col1">char (single byte)</entry>
              <entry colname="col2">GppcChar</entry>
              <entry colname="col3">GppcOidChar</entry>
            </row>
            <row>
              <entry colname="col1">int2/smallint</entry>
              <entry colname="col2">GppcInt2</entry>
              <entry colname="col3">GppcOidInt2</entry>
            </row>
            <row>
              <entry colname="col1">int4/integer</entry>
              <entry colname="col2">GppcInt4</entry>
              <entry colname="col3">GppcOidInt4</entry>
            </row>
            <row>
              <entry colname="col1">int8/bigint</entry>
              <entry colname="col2">GppcInt8</entry>
              <entry colname="col3">GppcOidInt8</entry>
            </row>
            <row>
              <entry colname="col1">float4/real</entry>
              <entry colname="col2">GppcFloat4</entry>
              <entry colname="col3">GppcOidFloat4</entry>
            </row>
            <row>
              <entry colname="col1">float8/double</entry>
              <entry colname="col2">GppcFloat8</entry>
              <entry colname="col3">GppcOidFloat8</entry>
            </row>
            <row>
              <entry colname="col1">text</entry>
              <entry colname="col2">*GppcText</entry>
              <entry colname="col3">GppcOidText</entry>
            </row>
            <row>
              <entry colname="col1">varchar</entry>
              <entry colname="col2">*GppcVarChar</entry>
              <entry colname="col3">GppcOidVarChar</entry>
            </row>
            <row>
              <entry colname="col1">char</entry>
              <entry colname="col2">*GppcBpChar</entry>
              <entry colname="col3">GppcOidBpChar</entry>
            </row>
            <row>
              <entry colname="col1">bytea</entry>
              <entry colname="col2">*GppcBytea</entry>
              <entry colname="col3">GppcOidBytea</entry>
            </row>
            <row>
              <entry colname="col1">numeric</entry>
              <entry colname="col2">*GppcNumeric</entry>
              <entry colname="col3">GppcOidNumeric</entry>
            </row>
            <row>
              <entry colname="col1">date</entry>
              <entry colname="col2">GppcDate</entry>
              <entry colname="col3">GppcOidDate</entry>
            </row>
            <row>
              <entry colname="col1">time</entry>
              <entry colname="col2">GppcTime</entry>
              <entry colname="col3">GppcOidTime</entry>
            </row>
            <row>
              <entry colname="col1">timetz</entry>
              <entry colname="col2">*GppcTimeTz</entry>
              <entry colname="col3">GppcOidTimeTz</entry>
            </row>
            <row>
              <entry colname="col1">timestamp</entry>
              <entry colname="col2">GppcTimestamp</entry>
              <entry colname="col3">GppcOidTimestamp</entry>
            </row>
            <row>
              <entry colname="col1">timestamptz</entry>
              <entry colname="col2">GppcTimestampTz</entry>
              <entry colname="col3">GppcOidTimestampTz</entry>
            </row>
            <row>
              <entry colname="col1">anytable</entry>
              <entry colname="col2">GppcAnyTable</entry>
              <entry colname="col3">GppcOidAnyTable</entry>
            </row>
            <row>
              <entry colname="col1">oid</entry>
              <entry colname="col2">GppcOid</entry>
              <entry colname="col3"></entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p> </p>
        <p>The GPPC API treats text, numeric, and timestamp data types specially,
           providing functions to operate on these types.</p>
        <p>Example GPPC base data type declarations:<codeblock>GppcText       message;
GppcInt4       arg1;
GppcNumeric    total_sales;</codeblock></p>
        <p>The GPPC API defines functions to convert between the generic
          <codeph>GppcDatum</codeph> type and the GPPC specific types. For
          example, to convert from an integer to a datum:<codeblock>
GppcInt4 num = 13;
GppcDatum num_dat = GppcInt4GetDatum(num);</codeblock></p>
      </body>
      <topic id="topic_composite" xml:lang="en">
        <title id="py217167">Composite Types</title>
        <body>
          <p>A composite data type represents the structure of a row or record,
            and is comprised of a list of field names and their data types.
            This structure information is typically referred to as a tuple
            descriptor. An instance of a composite type is typically referred
            to as a tuple or row. A tuple does not have a fixed layout and can
            contain null fields.</p>
          <p>The GPPC API provides an interface that you can use to define
            the structure of, to access, and to set tuples. You will use this
            interface when your GPPC function takes a table as an input
            argument or returns table or set of record types. Using tuples
            in table and set returning functions is covered later in this
            topic.</p>
        </body>
      </topic>
    </topic>

    <topic id="topic_argres" xml:lang="en">
      <title id="py217167">Function Declaration, Arguments, and Results</title>
      <body>
        <p>The GPPC API relies on macros to declare functions and to simplify
          the passing of function arguments and results. These macros include:</p>

        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="77*"/>
          <colspec colname="col2" colnum="2" colwidth="86*"/>
          <colspec colname="col3" colnum="3" colwidth="144*"/>
          <thead>
            <row>
              <entry colname="col1">Task</entry>
              <entry colname="col2">Macro Signature</entry>
              <entry colname="col3">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">Make a function SQL-invokable</entry>
              <entry colname="col2"><codeph>GPPC_FUNCTION_INFO(<varname>function_name</varname>)</codeph></entry>
              <entry colname="col3">Glue to make function <codeph><varname>function_name</varname></codeph> SQL-invokable.</entry>
            </row>
            <row>
              <entry colname="col1">Declare a function</entry>
              <entry colname="col2"><codeph>GppcDatum <varname>function_name</varname>(GPPC_FUNCTION_ARGS)</codeph></entry>
              <entry colname="col3">Declare a GPPC function named <codeph><varname>function_name</varname></codeph>; every function must have this same signature.</entry>
            </row>
            <row>
              <entry colname="col1">Return the number of arguments</entry>
              <entry colname="col2"><codeph>GPPC_NARGS()</codeph></entry>
              <entry colname="col3">Return the number of arguments passed to the function.</entry>
            </row>
            <row>
              <entry colname="col1">Fetch an argument</entry>
              <entry colname="col2"><codeph>GPPC_GETARG_&lt;ARGTYPE&gt;(<varname>arg_num</varname>)</codeph></entry>
              <entry colname="col3">Fetch the value of argument number <varname>arg_num</varname> (starts at 0), where <codeph>&lt;ARGTYPE&gt;</codeph> identifies the data type of the argument. For example, <codeph>GPPC_GETARG_FLOAT8(0)</codeph>.</entry>
            </row>
            <row>
              <entry colname="col1">Fetch and make a copy of a text-type argument</entry>
              <entry colname="col2"><codeph>GPPC_GETARG_&lt;ARGTYPE&gt;_COPY(<varname>arg_num</varname>)</codeph></entry>
              <entry colname="col3">Fetch and make a copy of the value of argument number <varname>arg_num</varname> (starts at 0). <codeph>&lt;ARGTYPE&gt;</codeph> identifies the text type (text, varchar, bpchar, bytea). For example, <codeph>GPPC_GETARG_BYTEA_COPY(1)</codeph>.</entry>
            </row>
            <row>
              <entry colname="col1">Determine if an argument is NULL</entry>
              <entry colname="col2"><codeph>GPPC_ARGISNULL(<varname>arg_num</varname>)</codeph></entry>
              <entry colname="col3">Return whether or not argument number <codeph><varname>arg_num</varname></codeph> is NULL.</entry>
            </row>
            <row>
              <entry colname="col1">Return a result</entry>
              <entry colname="col2"><codeph>GPPC_RETURN_&lt;ARGTYPE&gt;(<varname>return_val</varname>)</codeph></entry>
              <entry colname="col3">Return the value <codeph><varname>return_val</varname></codeph>, where <codeph>&lt;ARGTYPE&gt;</codeph> identifies the data type of the return value. For example, <codeph>GPPC_RETURN_INT4(131)</codeph>.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p>  </p>
         <p>When you define and implement your GPPC function, you must declare it
           with the GPPC API using the two declarations identified
           above. For example, to declare a GPPC function named
           <codeph>add_int4s()</codeph>:<codeblock>GPPC_FUNCTION_INFO(add_int4s);
GppcDatum add_int4s(GPPC_FUNCTION_ARGS);

GppcDatum
add_int4s(GPPC_FUNCTION_ARGS)
{
  // code here
}</codeblock></p>
        <p>If the <codeph>add_int4s()</codeph> function takes two input
          arguments of type <codeph>int4</codeph>, you use the
          <codeph>GPPC_GETARG_INT4(<varname>arg_num</varname>)</codeph> macro
          to access the argument values. The argument index starts at 0.
          For example:<codeblock>GppcInt4  first_int = GPPC_GETARG_INT4(0);
GppcInt4  second_int = GPPC_GETARG_INT4(1);</codeblock>  </p>
        <p>If <codeph>add_int4s()</codeph> returns the sum of the two input
          arguments, you use the <codeph>GPPC_RETURN_INT8(<varname>return_val</varname>)</codeph>
          macro to return this sum. For example:<codeblock>GppcInt8  sum = first_int + second_int;
GPPC_RETURN_INT8(sum);</codeblock>  </p>
         <p>The complete GPPC function:<codeblock>GPPC_FUNCTION_INFO(add_int4s);
GppcDatum add_int4s(GPPC_FUNCTION_ARGS);

GppcDatum
add_int4s(GPPC_FUNCTION_ARGS)
{
  // get input arguments
  GppcInt4    first_int = GPPC_GETARG_INT4(0);
  GppcInt4    second_int = GPPC_GETARG_INT4(1);

  // add the arguments
  GppcInt8    sum = first_int + second_int;

  // return the sum
  GPPC_RETURN_INT8(sum);
}</codeblock></p>
      </body>
    </topic>

    <topic id="topic_mem" xml:lang="en">
      <title id="py217167">Memory Handling</title>
      <body>
        <p>The GPPC API provides functions that you use to allocate and free
          memory, including text memory. You must use these functions for all
          memory operations.</p>
        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="86*"/>
          <colspec colname="col2" colnum="2" colwidth="77*"/>
          <thead>
            <row>
              <entry colname="col1">Function Name</entry>
              <entry colname="col2">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">void *GppcAlloc( size_t <varname>num</varname> )</entry>
              <entry colname="col2">Allocate <varname>num</varname> bytes of uninitialized memory.</entry>
            </row>
            <row>
              <entry colname="col1">void *GppcAlloc0( size_t <varname>num</varname> )</entry>
              <entry colname="col2">Allocate <varname>num</varname> bytes of 0-initialized memory.</entry>
            </row>
            <row>
              <entry colname="col1">void *GppcRealloc( void *<varname>ptr</varname>, size_t <varname>num</varname> )</entry>
              <entry colname="col2">Resize pre-allocated memory.</entry>
            </row>
            <row>
              <entry colname="col1">void GppcFree( void *<varname>ptr</varname> )</entry>
              <entry colname="col2">Free allocated memory.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p>After you allocate memory, you can use system functions such as
          <codeph>memcpy()</codeph> to set the data.</p>
        <p>The following example allocates an array of
          <codeph>GppcDatum</codeph>s and sets the array to datum versions
          of the function input arguments:<codeblock>GppcDatum  *values;
int attnum = GPPC_NARGS();

// allocate memory for attnum values
values = GppcAlloc( sizeof(GppcDatum) * attnum );

// set the values
for( int i=0; i&lt;attnum; i++ ) {
    GppcDatum d = GPPC_GETARG_DATUM(i);
    values[i] = d;
}</codeblock></p>

        <p>When you allocate memory for a GPPC function, you allocate it in
          the current context. The GPPC API includes functions to return, 
          create, switch, and reset memory contexts.</p>
        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="100*"/>
          <colspec colname="col2" colnum="2" colwidth="63*"/>
          <thead>
            <row>
              <entry colname="col1">Function Name</entry>
              <entry colname="col2">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">GppcMemoryContext GppcGetCurrentMemoryContext(void)</entry>
              <entry colname="col2">Return the current memory context.</entry>
            </row>
            <row>
              <entry colname="col1">GppcMemoryContext GppcMemoryContextCreate(GppcMemoryContext <varname>parent</varname>)</entry>
              <entry colname="col2">Create a new memory context under <varname>parent</varname>.</entry>
            </row>
            <row>
              <entry colname="col1">GppcMemoryContext GppcMemoryContextSwitchTo(GppcMemoryContext <varname>context</varname>)</entry>
              <entry colname="col2">Switch to the memory context <varname>context</varname>.</entry>
            </row>
            <row>
              <entry colname="col1">void GppcMemoryContextReset(GppcMemoryContext <varname>context</varname>)</entry>
              <entry colname="col2">Reset (free) the memory in  memory context <varname>context</varname>.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p>Greenplum Database typically calls a SQL-invoked function in a
          per-tuple context that it creates and deletes every time the server
          backend processes a table row. Do not assume that memory allocated
          in the current memory context is available across multiple function
          calls.</p>
      </body>
    </topic>

    <topic id="topic_varlentext" xml:lang="en">
      <title id="py217167">Working With Variable-Length Text Types</title>
      <body>
        <p>The GPPC API supports the variable length text, varchar, blank
          padded, and byte array types. You must use the GPPC API-provided
          functions when you operate on these data types. Variable text
          manipulation functions provided in the GPPC API include those to
          allocate memory for, determine string length of, get string pointers
          for, and access these types:</p>
          <table id="in201681">
          <tgroup cols="2">
            <colspec colname="col1" colnum="1" colwidth="105*"/>
            <colspec colname="col2" colnum="2" colwidth="75*"/>
            <thead>
              <row>
                <entry colname="col1">Function Name</entry>
                <entry colname="col2">Description</entry>
              </row>
            </thead>
            <tbody>
            <row>
              <entry colname="col1">GppcText GppcAllocText( size_t <varname>len</varname> )<p>GppcVarChar GppcAllocVarChar( size_t <varname>len</varname> )</p><p>GppcBpChar GppcAllocBpChar( size_t <varname>len</varname> )</p><p>GppcBytea GppcAllocBytea( size_t <varname>len</varname> )</p></entry>
              <entry colname="col2">Allocate <varname>len</varname> bytes of memory for the varying length type.</entry>
            </row>
            <row>
              <entry colname="col1">size_t GppcGetTextLength( GppcText <varname>s</varname> )<p>size_t GppcGetVarCharLength( GppcVarChar <varname>s</varname> )</p><p>size_t GppcGetBpCharLength( GppcBpChar <varname>s</varname> )</p><p>size_t GppcGetByteaLength( GppcBytea <varname>b</varname> )</p></entry>
              <entry colname="col2">Return the number of bytes in the memory chunk.</entry>
            </row>
              <row>
                <entry colname="col1">char *GppcGetTextPointer( GppcText <varname>s</varname> )<p>char *GppcGetVarCharPointer( GppcVarChar <varname>s</varname> )</p><p>char *GppcGetBpCharPointer( GppcBpChar <varname>s</varname> )</p><p>char *GppcGetByteaPointer( GppcBytea <varname>b</varname> )</p></entry>
                <entry colname="col2">Return a string pointer to the head of the memory chunk. The string is not null-terminated.</entry>
              </row>
              <row>
                <entry colname="col1">char *GppcTextGetCString( GppcText <varname>s</varname> )<p>char *GppcVarCharGetCString( GppcVarChar <varname>s</varname> )</p><p>char *GppcBpCharGetCString( GppcBpChar <varname>s</varname> )</p></entry>
                <entry colname="col2">Return a string pointer to the head of the memory chunk. The string is null-terminated.</entry>
              </row>
              <row>
                <entry colname="col1">GppcText *GppcCStringGetText( const char *<varname>s</varname> )<p>GppcVarChar *GppcCStringGetVarChar( const char *<varname>s</varname> )</p><p>GppcBpChar *GppcCStringGetBpChar( const char *<varname>s</varname> )</p></entry>
                <entry colname="col2">Build a varying-length type from a character string.</entry>
              </row>
            </tbody>
          </tgroup>
          </table>
          <p>Memory returned by the <codeph>GppcGet&lt;VLEN_ARGTYPE>Pointer()</codeph>
            functions may point to actual database content. Do not modify the
            memory content. The GPPC API provides functions to allocate memory
            for these types should you require it. After you allocate memory,
            you can use system functions such as <codeph>memcpy()</codeph>
            to set the data.</p>
          <p>The following example manipulates text input arguments and
            allocates and sets result memory for a text string concatenation
            operation:<codeblock>GppcText first_textstr = GPPC_GETARG_TEXT(0);
GppcText second_textstr = GPPC_GETARG_TEXT(1);

// determine the size of the concatenated string and allocate
// text memory of this size
size_t arg0_len = GppcGetTextLength(first_textstr);
size_t arg1_len = GppcGetTextLength(second_textstr);
GppcText retstring = GppcAllocText(arg0_len + arg1_len);

// construct the concatenated return string; copying each string
// individually
memcpy(GppcGetTextPointer(retstring), GppcGetTextPointer(first_textstr), arg0_len);
memcpy(GppcGetTextPointer(retstring) + arg0_len, GppcGetTextPointer(second_textstr), arg1_len);
</codeblock></p>
        </body>
    </topic>

    <topic id="topic_errrpt" xml:lang="en">
      <title id="py217167">Error Reporting and Logging</title>
      <body>
        <p>The GPPC API provides error reporting and logging functions. The
          API defines reporting levels equivalent to those in Greenplum
          Database:<codeblock>typedef enum GppcReportLevel
{
        GPPC_DEBUG1                             = 10,
        GPPC_DEBUG2                             = 11,
        GPPC_DEBUG3                             = 12,
        GPPC_DEBUG4                             = 13,
        GPPC_DEBUG                              = 14,
        GPPC_LOG                                = 15,
        GPPC_INFO                               = 17,
        GPPC_NOTICE                             = 18,
        GPPC_WARNING                    	= 19,
        GPPC_ERROR                              = 20,
} GppcReportLevel;
</codeblock>(The Greenplum Database <xref href="../config_params/guc-list.xml#client_min_messages"><codeph>client_min_messages</codeph></xref>
          server configuration parameter governs the current client logging
          level. The <xref href="../config_params/guc-list.xml#client_min_messages"><codeph>log_min_messages</codeph></xref>
          configuration parameter governs the current log-to-logfile level.)</p>
        <p>A GPPC report includes the report level, a report message, and an
          optional report callback function.</p>
        <p>Reporting and handling functions provide by the GPPC API include:</p>
        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="80*"/>
          <colspec colname="col2" colnum="2" colwidth="83*"/>
          <thead>
            <row>
              <entry colname="col1">Function Name</entry>
              <entry colname="col2">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">GppcReport()</entry>
              <entry colname="col2">Format and print/log a string of the specified report level.</entry>
            </row>
            <row>
              <entry colname="col1">GppcInstallReportCallback()</entry>
              <entry colname="col2">Register/install a report callback function.</entry>
            </row>
            <row>
              <entry colname="col1">GppcUninstallReportCallback()</entry>
              <entry colname="col2">Uninstall a report callback function.</entry>
            </row>
            <row>
              <entry colname="col1">GppcGetReportLevel()</entry>
              <entry colname="col2">Retrieve the level from an error report.</entry>
            </row>
            <row>
              <entry colname="col1">GppcGetReportMessage()</entry>
              <entry colname="col2">Retrieve the message from an error report.</entry>
            </row>
            <row>
              <entry colname="col1">GppcCheckForInterrupts()</entry>
              <entry colname="col2">Error out if an interrupt is pending.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p> </p>
        <p>The <codeph>GppcReport()</codeph> function signature
          is:<codeblock>void GppcReport(GppcReportLevel elevel, const char *fmt, ...);</codeblock></p>
        <p><codeph>GppcReport()</codeph> takes a format string input argument
          similar to <codeph>printf()</codeph>. The following example generates
          an error level report message that formats a GPPC text argument:
          <codeblock>GppcText  uname = GPPC_GETARG_TEXT(1);
GppcReport(GPPC_ERROR, "Unknown user name: %s", GppcTextGetCString(uname));</codeblock></p>
        <p>Refer to the <xref href="https://github.com/greenplum-db/gpdb/tree/master/src/interfaces/gppc/test" format="html" scope="external">GPPC example code</xref>
          for example report callback handlers.</p>
      </body>
    </topic>

    <topic id="topic_spi" xml:lang="en">
      <title id="py217167">SPI Functions</title>
      <body>
        <p>The Greenplum Database Server Programming Interface (SPI) provides
          writers of C/C++ functions the ability to run SQL commands within a
          GPPC function. For additional information on SPI functions, refer to
           <xref href="https://www.postgresql.org/docs/9.4/spi.html"
             scope="external"
             format="html">Server Programming Interface</xref>
            in the PostgreSQL documentation.</p>
       <p>The GPPC API exposes a subset of PostgreSQL SPI functions. This
         subset enables you to issue SPI queries and retrieve SPI result
         values in your GPPC function. The GPPC SPI wrapper functions are:</p>
        <table id="in201681">
        <tgroup cols="4">
          <colspec colname="col1" colnum="1" colwidth="40*"/>
          <colspec colname="col2" colnum="2" colwidth="57"/>
          <colspec colname="col3" colnum="3" colwidth="77*"/>
          <thead>
            <row>
              <entry colname="col1">SPI Function Name</entry>
              <entry colname="col2">GPPC Function Name</entry>
              <entry colname="col3">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">SPI_connect()</entry>
              <entry colname="col2">GppcSPIConnect()</entry>
              <entry colname="col3">Connect to the Greenplum Database server programming interface.</entry>
            </row>
            <row>
              <entry colname="col1">SPI_finish()</entry>
              <entry colname="col2">GppcSPIFinish()</entry>
              <entry colname="col3">Disconnect from the Greenplum Database server programming interface.</entry>
            </row>
            <row>
              <entry colname="col1">SPI_exec()</entry>
              <entry colname="col2">GppcSPIExec()</entry>
              <entry colname="col3">Run a SQL statement, returning the number of rows.</entry>
            </row>
            <row>
              <entry colname="col1" morerows="3">SPI_getvalue()</entry>
              <entry colname="col2">GppcSPIGetValue()</entry>
              <entry colname="col3">Retrieve the value of a specific attribute by number from a SQL result as a character string.</entry>
            </row>
            <row>
              <entry colname="col2">GppcSPIGetDatum()</entry>
              <entry colname="col3">Retrieve the value of a specific attribute by number from a SQL result as a <codeph>GppcDatum</codeph>.</entry>
            </row>
            <row>
              <entry colname="col2">GppcSPIGetValueByName()</entry>
              <entry colname="col3">Retrieve the value of a specific attribute by name from a SQL result as a character string.</entry>
            </row>
            <row>
              <entry colname="col2">GppcSPIGetDatumByName()</entry>
              <entry colname="col3">Retrieve the value of a specific attribute by name from a SQL result as a <codeph>GppcDatum</codeph>.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p>  </p>
        <p>When you create a GPPC function that accesses the server
          programming interface, your function should comply with the following
          flow:<codeblock>GppcSPIConnect();
GppcSPIExec(...)
// process the results - GppcSPIGetValue(...), GppcSPIGetDatum(...)
GppcSPIFinish()</codeblock></p>
        <p>You use <codeph>GppcSPIExec()</codeph> to run SQL statements in your GPPC function. When
          you call this function, you also identify the maximum number of rows to return. The
          function signature of <codeph>GppcSPIExec()</codeph>
          is:<codeblock>GppcSPIResult GppcSPIExec(const char *sql_statement, long rcount);</codeblock></p>
        <p><codeph>GppcSPIExec()</codeph> returns a <codeph>GppcSPIResult</codeph>
          structure. This structure represents SPI result data. It includes a
          pointer to the data, information about the number of rows processed,
          a counter, and a result code. The GPPC API defines this structure as
          follows:<codeblock>typedef struct GppcSPIResultData
{
    struct GppcSPITupleTableData   *tuptable;
    uint32_t                       processed;
    uint32_t                       current;
    int                            rescode;
} GppcSPIResultData;
typedef GppcSPIResultData *GppcSPIResult;</codeblock></p>
        <p>You can set and use the <codeph>current</codeph> field in the
          <codeph>GppcSPIResult</codeph> structure to examine each row of
          the <codeph>tuptable</codeph> result data.</p>
        <p>The following code excerpt uses the GPPC API to connect to SPI, run a simple query, loop
          through query results, and finish
          processing:<codeblock>GppcSPIResult   result;
char            *attname = "id";
char            *query = "SELECT i, 'foo' || i AS val FROM generate_series(1, 10)i ORDER BY 1";
bool            isnull = true;

// connect to SPI
if( GppcSPIConnect() &lt; 0 ) {
    GppcReport(GPPC_ERROR, "cannot connect to SPI");
}

// execute the query, returning all rows
result = GppcSPIExec(query, 0);

// process result
while( result->current &lt; result->processed ) {
    // get the value of attname column as a datum, making a copy
    datum = GppcSPIGetDatumByName(result, attname, &amp;isnull, true);

    // do something with value

    // move on to next row
    result->current++;
}

// complete processing
GppcSPIFinish();
</codeblock></p>
      </body>
    </topic>

    <topic id="topic_tuple" xml:lang="en">
      <title id="py21716799">About Tuple Descriptors and Tuples</title>
      <body>
        <p>A table or a set of records contains one or more tuples (rows).
          The structure of each attribute of a tuple is defined by a tuple
          descriptor. A tuple descriptor defines the following for each
          attribute in the tuple:<ul>
           <li>attribute name</li>
           <li>object identifier of the attribute data type</li>
           <li>byte length of the attribute data type</li>
           <li>object identifier of the attribute modifer</li>
        </ul></p>
        <p>The GPPC API defines an abstract type, <codeph>GppcTupleDesc</codeph>,
          to represent a tuple/row descriptor. The API also provides functions
          that you can use to create, access, and set tuple descriptors:</p>
        <table id="in201681">
          <tgroup cols="2">
            <colspec colname="col1" colnum="1" colwidth="65*"/>
            <colspec colname="col2" colnum="2" colwidth="105*"/>
            <thead>
              <row>
                <entry colname="col1">Function Name</entry>
                <entry colname="col2">Description</entry>
              </row>
            </thead>
            <tbody>
              <row>
                <entry colname="col1">GppcCreateTemplateTupleDesc()</entry>
                <entry colname="col2">Create an empty tuple descriptor with a specified number of attributes.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescInitEntry()</entry>
                <entry colname="col2">Add an attribute to the tuple descriptor at a specified position.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescNattrs()</entry>
                <entry colname="col2">Fetch the number of attributes in the tuple descriptor.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescAttrName()</entry>
                <entry colname="col2">Fetch the name of the attribute in a specific position (starts at 0) in the tuple descriptor.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescAttrType()</entry>
                <entry colname="col2">Fetch the type object identifier of the attribute in a specific position (starts at 0) in the tuple descriptor.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescAttrLen()</entry>
                <entry colname="col2">Fetch the type length of an attribute in a specific position (starts at 0) in the tuple descriptor.</entry>
              </row>
              <row>
                <entry colname="col1">GppcTupleDescAttrTypmod()</entry>
                <entry colname="col2">Fetch the type modifier object identifier of an attribute in a specific position (starts at 0) in the tuple descriptor.</entry>
              </row>
            </tbody>
          </tgroup>
          </table>
             <p>  </p>
             <p>To construct a tuple descriptor, you first create a template,
               and then fill in the descriptor fields for each attribute.
               The signatures for these functions are:<codeblock>GppcTupleDesc GppcCreateTemplateTupleDesc(int natts);
void GppcTupleDescInitEntry(GppcTupleDesc desc, uint16_t attno,
                            const char *attname, GppcOid typid, int32_t typmod);</codeblock></p>
             <p>In some cases, you may want to initialize a tuple descriptor
               entry from an attribute definition in an existing tuple. The
               following functions fetch the number of attributes in a tuple
               descriptor, as well as the definition of a specific attribute
               (by number) in the descriptor:<codeblock>int GppcTupleDescNattrs(GppcTupleDesc tupdesc);
const char *GppcTupleDescAttrName(GppcTupleDesc tupdesc, int16_t attno);
GppcOid GppcTupleDescAttrType(GppcTupleDesc tupdesc, int16_t attno);
int16_t GppcTupleDescAttrLen(GppcTupleDesc tupdesc, int16_t attno);
int32_t GppcTupleDescAttrTypmod(GppcTupleDesc tupdesc, int16_t attno);</codeblock></p>
             <p>The following example initializes a two attribute tuple
               descriptor. The first attribute is initialized with the
               definition of an attribute from a different descriptor, and
               the second attribute is initialized to a boolean type attribute:
               <codeblock>GppcTupleDesc       tdesc;
GppcTupleDesc       indesc = some_input_descriptor;

// initialize the tuple descriptor with 2 attributes
tdesc = GppcCreateTemplateTupleDesc(2);

// use third attribute from the input descriptor
GppcTupleDescInitEntry(tdesc, 1, 
	       GppcTupleDescAttrName(indesc, 2),
	       GppcTupleDescAttrType(indesc, 2),
	       GppcTupleDescAttrTypmod(indesc, 2));

// create the boolean attribute
GppcTupleDescInitEntry(tdesc, 2, "is_active", GppcOidBool, 0);
</codeblock></p>
        <p>The GPPC API defines an abstract type, <codeph>GppcHeapTuple</codeph>,
          to represent a tuple/record/row. A tuple is defined by its tuple
          descriptor, the value for each tuple attribute, and an indicator
          of whether or not each value is NULL.</p>
        <p>The GPPC API provides functions that you can use to set and access
          a tuple and its attributes:</p>
        <table id="in201681">
          <tgroup cols="2">
            <colspec colname="col1" colnum="1" colwidth="65*"/>
            <colspec colname="col2" colnum="2" colwidth="105*"/>
            <thead>
              <row>
                <entry colname="col1">Function Name</entry>
                <entry colname="col2">Description</entry>
              </row>
            </thead>
            <tbody>
              <row>
                <entry colname="col1">GppcHeapFormTuple()</entry>
                <entry colname="col2">Form a tuple from an array of <codeph>GppcDatum</codeph>s.</entry>
              </row>
              <row>
                <entry colname="col1">GppcBuildHeapTupleDatum()</entry>
                <entry colname="col2">Form a <codeph>GppcDatum</codeph> tuple from an array of <codeph>GppcDatum</codeph>s.</entry>
              </row>
              <row>
                <entry colname="col1">GppcGetAttributeByName()</entry>
                <entry colname="col2">Fetch an attribute from the tuple by name.</entry>
              </row>
              <row>
                <entry colname="col1">GppcGetAttributeByNum()</entry>
                <entry colname="col2">Fetch an attribute from the tuple by number (starts at 1).</entry>
              </row>
            </tbody>
          </tgroup>
          </table>
             <p>  </p>
             <p>The signatures for the tuple-building GPPC functions are:<codeblock>GppcHeapTuple GppcHeapFormTuple(GppcTupleDesc tupdesc, GppcDatum *values, bool *nulls);
GppcDatum    GppcBuildHeapTupleDatum(GppcTupleDesc tupdesc, GppcDatum *values, bool *nulls);</codeblock></p>
             <p>The following code excerpt constructs a <codeph>GppcDatum</codeph>
               tuple from the tuple descriptor in the above code example, and
                from integer and boolean input arguments to a function:<codeblock>GppcDatum intarg = GPPC_GETARG_INT4(0);
GppcDatum boolarg = GPPC_GETARG_BOOL(1);
GppcDatum result, values[2];
bool nulls[2] = { false, false };

// construct the values array
values[0] = intarg;
values[1] = boolarg;
result = GppcBuildHeapTupleDatum( tdesc, values, nulls );
</codeblock></p>
      </body>
    </topic>

    <topic id="topic_srf" xml:lang="en">
        <title id="py217167">Set-Returning Functions</title>
        <body>
          <p>Greenplum Database UDFs whose signatures include
            <codeph>RETURNS SETOF RECORD</codeph> or
            <codeph>RETURNS TABLE( ... )</codeph> are set-returning functions.</p>
          <p>The GPPC API provides support for returning sets (for example, multiple
            rows/tuples) from a GPPC function. Greenplum Database calls a
            set-returning function (SRF) once for each row or item. The
            function must save enough state to remember what it was doing
            and to return the next row on each call. Memory that you allocate
            in the SRF context must survive across multiple function calls.</p>
          <p>The GPPC API provides macros and functions to help keep track
            of and set this context, and to allocate SRF memory. They include:</p>
        <table id="in201681">
        <tgroup cols="2">
          <colspec colname="col1" colnum="1" colwidth="40*"/>
          <colspec colname="col2" colnum="2" colwidth="60*"/>
          <thead>
            <row>
              <entry colname="col1">Function/Macro Name</entry>
              <entry colname="col2">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">GPPC_SRF_RESULT_DESC()</entry>
              <entry colname="col2">Get the output row tuple descriptor for this SRF. The result tuple descriptor is determined by an output table definition or a <codeph>DESCRIBE</codeph> function.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_SRF_IS_FIRSTCALL()</entry>
              <entry colname="col2">Determine if this is the first call to the SRF.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_SRF_FIRSTCALL_INIT()</entry>
              <entry colname="col2">Initialize the SRF context.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_SRF_PERCALL_SETUP()</entry>
              <entry colname="col2">Restore the context on each call to the SRF.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_SRF_RETURN_NEXT()</entry>
              <entry colname="col2">Return a value from the SRF and continue processing.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_SRF_RETURN_DONE()</entry>
              <entry colname="col2">Signal that SRF processing is complete.</entry>
            </row>
            <row>
              <entry colname="col1">GppSRFAlloc()</entry>
              <entry colname="col2">Allocate memory in this SRF context.</entry>
            </row>
            <row>
              <entry colname="col1">GppSRFAlloc0()</entry>
              <entry colname="col2">Allocate memory in this SRF context and initialize it to zero.</entry>
            </row>
            <row>
              <entry colname="col1">GppSRFSave()</entry>
              <entry colname="col2">Save user state in this SRF context.</entry>
            </row>
            <row>
              <entry colname="col1">GppSRFRestore()</entry>
              <entry colname="col2">Restore user state in this SRF context.</entry>
            </row>
          </tbody>
        </tgroup>
        </table>
        <p>  </p>
        <p>The <codeph>GppcFuncCallContext</codeph> structure provides the
          context for an SRF. You create this context on the first call to
          your SRF. Your set-returning GPPC function must retrieve the
          function context on each invocation. For example:<codeblock>// set function context
GppcFuncCallContext fctx;
if (GPPC_SRF_IS_FIRSTCALL()) {
    fctx = GPPC_SRF_FIRSTCALL_INIT();
}
fctx = GPPC_SRF_PERCALL_SETUP();
// process the tuple
</codeblock></p>
         <p>The GPPC function must provide the context when it returns a
           tuple result or to indicate that processing is complete. For 
           example:<codeblock>GPPC_SRF_RETURN_NEXT(fctx, result_tuple);
// or
GPPC_SRF_RETURN_DONE(fctx);</codeblock></p>

        <p>Use a <codeph>DESCRIBE</codeph> function to define the output
          tuple descriptor of a function that uses the <codeph>RETURNS SETOF RECORD</codeph> clause.
          Use the <codeph>GPPC_SRF_RESULT_DESC()</codeph> macro to get the
          output tuple descriptor of a function that uses the <codeph>RETURNS TABLE( ... )</codeph> clause.</p>
        <p>Refer to the <xref href="#topic_example_srf" type="topic" format="dita"/>
          for a set-returning function code and deployment example.</p>
      </body>
    </topic>

    <topic id="topic_tblfunc" xml:lang="en">
      <title id="py217167">Table Functions</title>
      <body>
        <p>The GPPC API provides the <codeph>GppcAnyTable</codeph> type to
          pass a table to a function as an input argument, or to return a
          table as a function result.</p>
        <p>Table-related functions and macros provided in the GPPC API include:</p>
        <table id="in201681">
        <tgroup cols="2">
          <colspec colname="col1" colnum="1" colwidth="40*"/>
          <colspec colname="col2" colnum="2" colwidth="60*"/>
          <thead>
            <row>
              <entry colname="col1">Function/Macro Name</entry>
              <entry colname="col2">Description</entry>
            </row>
          </thead>
          <tbody>
            <row>
              <entry colname="col1">GPPC_GETARG_ANYTABLE()</entry>
              <entry colname="col2">Fetch an anytable function argument.</entry>
            </row>
            <row>
              <entry colname="col1">GPPC_RETURN_ANYTABLE()</entry>
              <entry colname="col2">Return the table.</entry>
            </row>
            <row>
              <entry colname="col1">GppcAnyTableGetTupleDesc()</entry>
              <entry colname="col2">Fetch the tuple descriptor for the table.</entry>
            </row>
            <row>
              <entry colname="col1">GppcAnyTableGetNextTuple()</entry>
              <entry colname="col2">Fetch the next row in the table.</entry>
            </row>
          </tbody>
        </tgroup>
      </table>
      <p>  </p>
      <p>You can use the <codeph>GPPC_GETARG_ANYTABLE()</codeph> macro to
        retrieve a table input argument. When you have access to the table,
        you can examine the tuple descriptor for the table using the
        <codeph>GppcAnyTableGetTupleDesc()</codeph> function. The signature
        of this function is:<codeblock>GppcTupleDesc GppcAnyTableGetTupleDesc(GppcAnyTable t);</codeblock></p>
       <p>For example, to retrieve the tuple descriptor of a table that
         is the first input argument to a function:<codeblock>GppcAnyTable     intbl;
GppcTupleDesc    in_desc;

intbl = GPPC_GETARG_ANYTABLE(0);
in_desc = GppcAnyTableGetTupleDesc(intbl);</codeblock></p>
      <p>The <codeph>GppcAnyTableGetNextTuple()</codeph> function fetches
        the next row from the table. Similarly, to retrieve the next tuple
        from the table above:<codeblock>GppcHeapTuple    ntuple;

ntuple = GppcAnyTableGetNextTuple(intbl);</codeblock></p>
      </body>
    </topic>

    <topic id="topic_limits" xml:lang="en">
      <title id="py217167">Limitations</title>
      <body>
        <p>The GPPC API does not support the following operators with Greenplum Database version 5.0.x:</p><ul>
          <li>integer || integer</li>
          <li>integer = text</li>
          <li>text &lt; integer</li>
        </ul>
      </body>
    </topic>

    <topic id="topic_samplecode" xml:lang="en">
      <title id="py217167">Sample Code</title>
      <body>
        <p>The <xref href="https://github.com/greenplum-db/gpdb/tree/master/src/interfaces/gppc/test" format="html" scope="external">gppc test</xref>
          directory in the Greenplum Database github repository includes
          sample GPPC code:</p><ul>
          <li><codeph>gppc_demo/</codeph> - sample code exercising GPPC SPI functions, error reporting, data type argument and return macros, set-returning functions, and encoding functions</li>
          <li><codeph>tabfunc_gppc_demo/</codeph> - sample code exercising GPPC table and set-returning functions</li>
        </ul>
      </body>
    </topic>

  </topic>

  <topic id="topic_build" xml:lang="en">
      <title id="py217167bbb">Building a GPPC Shared Library with PGXS</title>
      <body>
        <p>You compile functions that you write with the GPPC API into one
          or more shared libraries that the Greenplum Database server loads
          on demand.</p>
        <p>You can use the PostgreSQL build extension infrastructure (PGXS)
          to build the source code for your GPPC functions against a Greenplum
          Database installation. This framework automates common build rules
          for simple modules. If you have a more complicated use case, you
          will need to write your own build system.</p>
        <p>To use the PGXS infrastructure to generate a shared library for
          functions that you create with the GPPC API, create a simple
          <codeph>Makefile</codeph> that sets PGXS-specific variables.</p>
        <note>Refer to <xref href="https://www.postgresql.org/docs/9.4/extend-pgxs.html" format="html" scope="external">Extension Building Infrastructure</xref>
          in the PostgreSQL documentation for information about the
          <codeph>Makefile</codeph> variables supported by PGXS.</note>
        <p>For example, the following <codeph>Makefile</codeph> generates
          a shared library named <codeph>sharedlib_name.so</codeph> from
          two C source files named <codeph>src1.c</codeph> and <codeph>src2.c</codeph>:<codeblock>MODULE_big = sharedlib_name
OBJS = src1.o src2.o
PG_CPPFLAGS = -I$(shell $(PG_CONFIG) --includedir)
SHLIB_LINK = -L$(shell $(PG_CONFIG) --libdir) -lgppc

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)</codeblock></p>

        <p><codeph>MODULE_big</codeph> identifes the base name of the shared
          library generated by the <codeph>Makefile</codeph>.</p>
        <p><codeph>PG_CPPFLAGS</codeph> adds the Greenplum Database installation
          include directory to the compiler header file search path.</p>
        <p><codeph>SHLIB_LINK</codeph> adds the Greenplum Database installation
          library directory to the linker search path. This variable also adds
          the GPPC library (<codeph>-lgppc</codeph>) to the link command.</p>
        <p>The <codeph>PG_CONFIG</codeph> and <codeph>PGXS</codeph> variable
          settings and the <codeph>include</codeph> statement are required
          and typically reside in the last three lines of the
          <codeph>Makefile</codeph>.</p>
      </body>
  </topic>

  <topic id="topic_reg" xml:lang="en">
      <title id="py21716799">Registering a GPPC Function with Greenplum Database</title>
      <body>
        <p>Before users can invoke a GPPC function from SQL, you must
          register the function with Greenplum Database.</p>
        <p>Registering a GPPC function involves mapping the GPPC function
          signature to a SQL user-defined function. You define this mapping
          with the <codeph>CREATE FUNCTION .. AS </codeph> command specifying
          the GPPC shared library name. You may choose to use the same name
          or differing names for the GPPC and SQL functions.</p>
        <p>Sample <codeph>CREATE FUNCTION ... AS </codeph> syntax follows:
          <codeblock>CREATE FUNCTION <varname>sql_function_name</varname>(<varname>arg</varname>[, ...]) RETURNS <varname>return_type</varname>
  AS '<varname>shared_library_path</varname>'[, '<varname>gppc_function_name</varname>']
LANGUAGE C STRICT [WITH (DESCRIBE=<varname>describe_function</varname>)];</codeblock></p>
         <p>You may omit the shared library <codeph>.so</codeph> extension
           when you specify <codeph><varname>shared_library_path</varname></codeph>.</p>
        <p>The following command registers the example <codeph>add_int4s()</codeph>
          function referenced earlier in this topic to a SQL UDF named
          <codeph>add_two_int4s_gppc()</codeph> if the GPPC function was compiled
          and linked in a shared library named <codeph>gppc_try.so</codeph>:
          <codeblock>CREATE FUNCTION add_two_int4s_gppc(int4, int4) RETURNS int8
  AS 'gppc_try.so', 'add_int4s'
LANGUAGE C STRICT;</codeblock></p>
      </body>

  <topic id="topic_dynload" xml:lang="en">
    <title id="py217167bx">About Dynamic Loading</title>
    <body>
      <p>You specify the name of the GPPC shared library in the SQL
        <codeph>CREATE FUNCTION ... AS</codeph> command to register a GPPC
        function in the shared library with Greenplum Database. The Greenplum
        Database dynamic loader loads a GPPC shared library file into memory
        the first time that a user invokes a user-defined function linked in
        that shared library. If you do not provide an absolute path to the
        shared library in the <codeph>CREATE FUNCTION ... AS</codeph>
        command, Greenplum Database attempts to locate the library using these
        ordered steps:</p><ol>
        <li>If the shared library file path begins with the string
          <codeph>$libdir</codeph>, Greenplum Database looks for the file
          in the PostgreSQL package library directory. Run the
          <codeph>pg_config --pkglibdir</codeph> command to determine the
          location of this directory.</li>
        <li>If the shared library file name is specified without a directory
          prefix, Greenplum Database searches for the file in the directory
          identified by the <codeph>dynamic_library_path</codeph> server
          configuration parameter value.</li>
        <li>The current working directory.</li></ol>
    </body>
  </topic>
  </topic>
  <topic id="topic_deploy" xml:lang="en">
      <title id="py21716799">Packaging and Deployment Considerations</title>
      <body>
        <p>You must package the GPPC shared library and SQL function
          registration script in a form suitable for deployment by the
          Greenplum Database administrator in the Greenplum cluster.
          Provide specific deployment instructions for your GPPC package.</p>
        <p>When you construct the package and deployment instructions, take
          into account the following:</p><ul>
          <li>Consider providing a shell script or program that the Greenplum
            Database administrator runs to both install the shared library to
            the desired file system location and register the GPPC functions.</li>
          <li>The GPPC shared library must be installed to the same file
            system location on the master host and on every segment host in the
            Greenplum Database cluster.</li>
          <li>The <codeph>gpadmin</codeph> user must have permission to
            traverse the complete file system path to the GPPC shared 
            library file.</li>
         <li>The file system location of your GPPC shared library after it
           is installed in the Greenplum Database deployment determines how
           you reference the shared library when you register a function in
           the library with the <codeph>CREATE FUNCTION ... AS</codeph>
           command.</li>
          <li> Create a <codeph>.sql</codeph> script file that registers
           a SQL UDF for each GPPC function in your GPPC shared library.
           The functions that you create in the <codeph>.sql</codeph>
           registration script must reference the deployment location of the
           GPPC shared library. Include this script in your GPPC deployment package.</li>
          <li>Document the instructions for running your GPPC package deployment
             script, if you provide one.</li>
          <li>Document the instructions for installing the GPPC shared library
            if you do not include this task in a package deployment script.</li>
          <li>Document the instructions for installing and running the function
            registration script if you do not include this task in a package
            deployment script.</li>
        </ul>
      </body>
  </topic>
  <topic id="topic_example_text" xml:lang="en">
    <title id="py217167">GPPC Text Function Example</title>
    <body>
      <p>In this example, you develop, build, and deploy a GPPC shared library
        and register and run a GPPC function named <codeph>concat_two_strings</codeph>.
        This function uses the GPPC API to concatenate two string arguments
        and return the result.</p>
      <p>You will develop the GPPC function on your Greenplum Database master
        host. Deploying the GPPC shared library that you create in this
        example requires administrative access to your Greenplum Database
        cluster.</p>
      <p>Perform the following procedure to run the example:</p><ol>
        <li>Log in to the Greenplum Database master host and set up your environment. For example:<codeblock>$ ssh gpadmin@&lt;gpmaster&gt;
gpadmin@gpmaster$ . /usr/local/greenplum-db/greenplum_path.sh</codeblock></li>
        <li>Create a work directory and navigate to the new directory. For example:<codeblock>gpadmin@gpmaster$ mkdir gppc_work
gpadmin@gpmaster$ cd gppc_work</codeblock></li>
        <li>Prepare a file for GPPC source code by opening the file in the editor of your choice. For example, to open a file named <codeph>gppc_concat.c</codeph> using <codeph>vi</codeph>:<codeblock>gpadmin@gpmaster$ vi gppc_concat.c</codeblock></li>
        <li>Copy/paste the following code into the file:<codeblock>#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include "gppc.h"

// make the function SQL-invokable
GPPC_FUNCTION_INFO(concat_two_strings);

// declare the function
GppcDatum concat_two_strings(GPPC_FUNCTION_ARGS);

GppcDatum
concat_two_strings(GPPC_FUNCTION_ARGS)
{
    // retrieve the text input arguments
    GppcText arg0 = GPPC_GETARG_TEXT(0);
    GppcText arg1 = GPPC_GETARG_TEXT(1);

    // determine the size of the concatenated string and allocate
    // text memory of this size
    size_t arg0_len = GppcGetTextLength(arg0);
    size_t arg1_len = GppcGetTextLength(arg1);
    GppcText retstring = GppcAllocText(arg0_len + arg1_len);

    // construct the concatenated return string
    memcpy(GppcGetTextPointer(retstring), GppcGetTextPointer(arg0), arg0_len);
    memcpy(GppcGetTextPointer(retstring) + arg0_len, GppcGetTextPointer(arg1), arg1_len);

    GPPC_RETURN_TEXT( retstring );
}</codeblock><p>The code declares and implements the <codeph>concat_two_strings()</codeph> function. It uses GPPC data types, macros, and functions to get the function arguments, allocate memory for the concatenated string, copy the arguments into the new string, and return the result.</p></li>
        <li>Save the file and exit the editor.</li>
        <li>Open a file named <codeph>Makefile</codeph> in the editor of your choice. Copy/paste the following text into the file:<codeblock>MODULE_big = gppc_concat
OBJS = gppc_concat.o

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)

PG_CPPFLAGS = -I$(shell $(PG_CONFIG) --includedir)
SHLIB_LINK = -L$(shell $(PG_CONFIG) --libdir) -lgppc
include $(PGXS)</codeblock></li>
        <li>Save the file and exit the editor.</li>
        <li>Build a GPPC shared library for the <codeph>concat_two_strings()</codeph> function. For example:<codeblock>gpadmin@gpmaster$ make all</codeblock><p>The <codeph>make</codeph> command generates a shared library file named <codeph>gppc_concat.so</codeph> in the current working directory.</p></li>
        <li>Copy the shared library to your Greenplum Database installation. You must have Greenplum Database administrative privileges to copy the file. For example:<codeblock>gpadmin@gpmaster$ cp gppc_concat.so /usr/local/greenplum-db/lib/postgresql/</codeblock></li>
        <li>Copy the shared library to every host in your Greenplum Database installation. For example, if <codeph>seghostfile</codeph> contains a list, one-host-per-line, of the segment hosts in your Greenplum Database cluster:<codeblock>gpadmin@gpmaster$ gpscp -v -f seghostfile /usr/local/greenplum-db/lib/postgresql/gppc_concat.so =:/usr/local/greenplum-db/lib/postgresql/gppc_concat.so</codeblock></li>
        <li>Open a <codeph>psql</codeph> session. For example:<codeblock>gpadmin@gpmaster$ psql -d testdb</codeblock></li>
        <li>Register the GPPC function named <codeph>concat_two_strings()</codeph> with Greenplum Database, For example, to map the Greenplum Database function <codeph>concat_with_gppc()</codeph> to the GPPC <codeph>concat_two_strings()</codeph> function:<codeblock>testdb=# CREATE FUNCTION concat_with_gppc(text, text) RETURNS text
  AS 'gppc_concat', 'concat_two_strings'
LANGUAGE C STRICT;</codeblock></li>
        <li>Run the <codeph>concat_with_gppc()</codeph> function. For example:<codeblock>testdb=# SELECT concat_with_gppc( 'happy', 'monday' );
 concat_with_gppc
------------------
 happymonday
(1 row)
</codeblock></li>
      </ol>
    </body>
  </topic>
  <topic id="topic_example_srf" xml:lang="en">
    <title id="py217167">GPPC Set-Returning Function Example</title>
    <body>
      <p>In this example, you develop, build, and deploy a GPPC shared library.
        You also create and run a <codeph>.sql</codeph> registration script
        for a GPPC function named <codeph>return_tbl()</codeph>. This function
        uses the GPPC API to take an input table with an integer and a text
        column, determine if the integer column is greater than 13, and
        returns a result table with the input integer column and a boolean
        column identifying whether or not the integer is greater than 13.
        <codeph>return_tbl()</codeph> utilizes GPPC API reporting and SRF
        functions and macros.</p>
      <p>You will develop the GPPC function on your Greenplum Database master
        host. Deploying the GPPC shared library that you create in this
        example requires administrative access to your Greenplum Database
        cluster.</p>
      <p>Perform the following procedure to run the example:</p><ol>
        <li>Log in to the Greenplum Database master host and set up your environment. For example:<codeblock>$ ssh gpadmin@&lt;gpmaster&gt;
gpadmin@gpmaster$ . /usr/local/greenplum-db/greenplum_path.sh</codeblock></li>
        <li>Create a work directory and navigate to the new directory. For example:<codeblock>gpadmin@gpmaster$ mkdir gppc_work
gpadmin@gpmaster$ cd gppc_work</codeblock></li>
        <li>Prepare a source file for GPPC code by opening the file in the editor of your choice. For example, to open a file named <codeph>gppc_concat.c</codeph> using <codeph>vi</codeph>:<codeblock>gpadmin@gpmaster$ vi gppc_rettbl.c</codeblock></li>
        <li>Copy/paste the following code into the file:<codeblock>#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include "gppc.h"

// initialize the logging level
GppcReportLevel level = GPPC_INFO;

// make the function SQL-invokable and declare the function
GPPC_FUNCTION_INFO(return_tbl);
GppcDatum return_tbl(GPPC_FUNCTION_ARGS);

GppcDatum
return_tbl(GPPC_FUNCTION_ARGS)
{
    GppcFuncCallContext	fctx;
    GppcAnyTable	intbl;
    GppcHeapTuple	intuple;
    GppcTupleDesc	in_tupdesc, out_tupdesc;
    GppcBool  		resbool = false;
    GppcDatum  		result, boolres, values[2];
    bool		nulls[2] = {false, false};

    // single input argument - the table
    intbl = GPPC_GETARG_ANYTABLE(0);

    // set the function context
    if (GPPC_SRF_IS_FIRSTCALL()) {
        fctx = GPPC_SRF_FIRSTCALL_INIT();
    }
    fctx = GPPC_SRF_PERCALL_SETUP();

    // get the tuple descriptor for the input table
    in_tupdesc  = GppcAnyTableGetTupleDesc(intbl);

    // retrieve the next tuple
    intuple = GppcAnyTableGetNextTuple(intbl);
    if( intuple == NULL ) {
      // no more tuples, conclude
      GPPC_SRF_RETURN_DONE(fctx);
    }

    // get the output tuple descriptor and verify that it is
    // defined as we expect
    out_tupdesc = GPPC_SRF_RESULT_DESC();
    if (GppcTupleDescNattrs(out_tupdesc) != 2                ||
        GppcTupleDescAttrType(out_tupdesc, 0) != GppcOidInt4 ||
        GppcTupleDescAttrType(out_tupdesc, 1) != GppcOidBool) {
        GppcReport(GPPC_ERROR, "INVALID out_tupdesc tuple");
    }

    // log the attribute names of the output tuple descriptor
    GppcReport(level, "output tuple descriptor attr0 name: %s", GppcTupleDescAttrName(out_tupdesc, 0));
    GppcReport(level, "output tuple descriptor attr1 name: %s", GppcTupleDescAttrName(out_tupdesc, 1));

    // retrieve the attribute values by name from the tuple
    bool text_isnull, int_isnull;
    GppcDatum intdat = GppcGetAttributeByName(intuple, "id", &amp;int_isnull);
    GppcDatum textdat = GppcGetAttributeByName(intuple, "msg", &amp;text_isnull);

    // convert datum to specific type
    GppcInt4 intarg = GppcDatumGetInt4(intdat);
    GppcReport(level, "id: %d", intarg);
    GppcReport(level, "msg: %s", GppcTextGetCString(GppcDatumGetText(textdat)));

    // perform the >13 check on the integer
    if( !int_isnull &amp;&amp; (intarg > 13) ) {
        // greater than 13?
        resbool = true;
        GppcReport(level, "id is greater than 13!");
    }

    // values are datums; use integer from the tuple and
    // construct the datum for the boolean return
    values[0] = intdat;
    boolres = GppcBoolGetDatum(resbool);
    values[1] = boolres;

    // build a datum tuple and return
    result = GppcBuildHeapTupleDatum(out_tupdesc, values, nulls);
    GPPC_SRF_RETURN_NEXT(fctx, result);

}</codeblock><p>The code declares and implements the <codeph>return_tbl()</codeph> function. It uses GPPC data types, macros, and functions to fetch the function arguments, examine tuple descriptors, build the return tuple, and return the result. The function also uses the SRF macros to keep track of the tuple context across function calls.</p></li>
        <li>Save the file and exit the editor.</li>
        <li>Open a file named <codeph>Makefile</codeph> in the editor of your choice. Copy/paste the following text into the file:<codeblock>MODULE_big = gppc_rettbl
OBJS = gppc_rettbl.o

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)

PG_CPPFLAGS = -I$(shell $(PG_CONFIG) --includedir)
SHLIB_LINK = -L$(shell $(PG_CONFIG) --libdir) -lgppc
include $(PGXS)</codeblock></li>
        <li>Save the file and exit the editor.</li>
        <li>Build a GPPC shared library for the <codeph>return_tbl()</codeph> function. For example:<codeblock>gpadmin@gpmaster$ make all</codeblock><p>The <codeph>make</codeph> command generates a shared library file named <codeph>gppc_rettbl.so</codeph> in the current working directory.</p></li>
        <li>Copy the shared library to your Greenplum Database installation. You must have Greenplum Database administrative privileges to copy the file. For example:<codeblock>gpadmin@gpmaster$ cp gppc_rettbl.so /usr/local/greenplum-db/lib/postgresql/</codeblock><p>This command copies the shared library to <codeph>$libdir</codeph></p></li>
        <li>Copy the shared library to every host in your Greenplum Database installation. For example, if <codeph>seghostfile</codeph> contains a list, one-host-per-line, of the segment hosts in your Greenplum Database cluster:<codeblock>gpadmin@gpmaster$ gpscp -v -f seghostfile /usr/local/greenplum-db/lib/postgresql/gppc_rettbl.so =:/usr/local/greenplum-db/lib/postgresql/gppc_rettbl.so</codeblock></li>
        <li>Create a <codeph>.sql</codeph> file to register the GPPC <codeph>return_tbl()</codeph> function. Open a file named <codeph>gppc_rettbl_reg.sql</codeph> in the editor of your choice.</li>
        <li>Copy/paste the following text into the file:<codeblock>CREATE FUNCTION rettbl_gppc(anytable) RETURNS TABLE(id int4, thirteen bool)
  AS 'gppc_rettbl', 'return_tbl'
LANGUAGE C STRICT;</codeblock></li>
        <li>Register the GPPC function by running the script you just created. For example, to register the function in a database named <codeph>testdb</codeph>:<codeblock>gpadmin@gpmaster$ psql -d testdb -f gppc_rettbl_reg.sql</codeblock></li>
        <li>Open a <codeph>psql</codeph> session. For example:<codeblock>gpadmin@gpmaster$ psql -d testdb</codeblock></li>
        <li>Create a table with some test data. For example:<codeblock>CREATE TABLE gppc_testtbl( id int, msg text );
INSERT INTO gppc_testtbl VALUES (1, 'f1');
INSERT INTO gppc_testtbl VALUES (7, 'f7');
INSERT INTO gppc_testtbl VALUES (10, 'f10');
INSERT INTO gppc_testtbl VALUES (13, 'f13');
INSERT INTO gppc_testtbl VALUES (15, 'f15');
INSERT INTO gppc_testtbl VALUES (17, 'f17');</codeblock></li>
        <li>Run the <codeph>rettbl_gppc()</codeph> function. For example:<codeblock>testdb=# SELECT * FROM rettbl_gppc(TABLE(SELECT * FROM gppc_testtbl));
 id | thirteen 
----+----------
  1 | f
  7 | f
 13 | f
 15 | t
 17 | t
 10 | f
(6 rows)
</codeblock></li>
      </ol>
    </body>
  </topic>
</topic>
